package com.itheima.shorturl.util;

import java.io.Serializable;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * @author andy
 * @version 1.0
 * @date 2021/5/18 9:04 上午
 * @description EnhancedComparator
 */
public interface EnhancedComparator<T> extends Comparator<T> {
    static <T> Comparator<T> lastIfPredicate(Predicate<T> predicate, Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(predicate, comparator);
    }

    class Comparators {
        private Comparators() {
            throw new AssertionError("no instances");
        }

        /**
         * Compares {@link Comparable} objects in natural order.
         *
         * @see Comparable
         */
        enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
            INSTANCE;

            @Override
            public int compare(Comparable<Object> c1, Comparable<Object> c2) {
                return c1.compareTo(c2);
            }

            @Override
            public Comparator<Comparable<Object>> reversed() {
                return Comparator.reverseOrder();
            }
        }

        /**
         * Null-friendly comparators
         */
        final static class NullComparator<T> implements Comparator<T>, Serializable {
            private static final long serialVersionUID = -7569533591570686392L;
            private final Predicate<T> predicate;
            // if null, non-null Ts are considered equal
            private final Comparator<T> real;

            @SuppressWarnings("unchecked")
            NullComparator(Predicate<T> predicate, Comparator<? super T> real) {
                this.predicate = predicate;
                this.real = (Comparator<T>) real;
            }

            @Override
            public int compare(T a, T b) {
                if (predicate.test(a)) {
                    return 1;
                } else if (predicate.test(b)) {
                        return -1;
                }else {
                    return (real == null) ? 0 : real.compare(a, b);
                }
            }

            @Override
            public Comparator<T> thenComparing(Comparator<? super T> other) {
                Objects.requireNonNull(other);
                return new Comparators.NullComparator<>(predicate, real == null ? other : real.thenComparing(other));
            }

            @Override
            public Comparator<T> reversed() {
                return new Comparators.NullComparator<>(predicate, real == null ? null : real.reversed());
            }
        }
    }
}

